fix: butterfly fleeing stuck state + HUD stat legend#89
Merged
biosynthart merged 6 commits intoJun 21, 2026
Conversation
- LMB click (tap, not drag) selects nearest entity via 3D raycast that accounts for flight altitude (birds, insects) - Selected entity pulses with bright highlight color in-world - Center-top HUD label shows species, state, and drive stats - Esc or click on empty ground deselects - Auto-deselect when selected entity dies Changes: - scenes/main.gd: click detection, raycast-to-point selection, HUD stats panel with per-type drive formatting - scenes/main.tscn: SelectionLabel node on HUD, updated help text - scripts/renderer.gd: highlight color pulse for selected entity
Server-side fixes: - FleeActor only fires on state entry (not every tick), preventing continuous target resets that trapped entities in FLEEING forever - MovementActor skips FLEEING entities so the guard actor can cleanly transition FLEEING -> IDLE when escape target is reached. Without this, MovementActor would set a wander target before the guard ran, keeping _target non-None and blocking the exit transition Client-side fixes (Godot): - Fixed inverted null-check in _evaluate_fleeing: 'best == null or flee_targets.has()' was wrong; corrected to 'best != null and flee_targets.has()' - Added flee direction caching (flee_dir + flee_dir_expiry) so entities keep running in the last known safe direction when the threat is momentarily not found (client/server position divergence) HUD improvement: - Added per-entity-type stat legend (LegendLabel) in top-right corner - Explains each icon: hunger, energy, hydration, health, growth, colony health, etc. with value ranges (0-100 or ticks) - Auto-shows/hides when selecting/deselecting entities
Both clients had the same issue as the Godot client: when the server says FLEEING but the client can't find a threat (position divergence, stale data), they fell through to wander mid-flee instead of keeping the escape direction. Added flee direction caching (fleeDirX/Y + fleeDirExpiry, 3s timeout) to both clients, matching the pattern already applied to Godot.
Multiple .py files had malformed module docstrings where the opening triple-quote was missing, causing Python to parse the indented docstring body as code (IndentationError/SyntaxError). Converted all affected headers to plain # comments, consistent with the rest of the codebase and matching the Godot/browser clients.
Godot 4 expects grow_horizontal/grow_vertical values 0-3 (Begin/Center/End/Both). The editor-created LegendLabel had value 4, causing two startup errors.
Valid values are Begin (0), Center (1), End (2). Changed to 1 (Center).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes multiple bugs where butterflies got permanently trapped in FLEEING state, and adds a stat legend to the selection HUD.
Bug: Butterflies stuck in FLEEING → slowly die of exhaustion
Root cause (server)
The engine runs phases in this order: Flow → Movement → Interactions → Guards. Two bugs combined to create a trap:
FleeActor re-fired every tick — as long as a predator was in sensory range, it emitted a new
SetTarget, resetting the escape position. The guard actor only exits FLEEING when_target is None, so_targetwas never cleared.MovementActor filled the gap — when the butterfly reached its escape target and
_targetwas cleared, MovementActor (running in Flow phase) immediately set a new wander target. The guard (running after Flow) then saw_targetwas set and never exited FLEEING.For butterflies with
floral_affinity, sensory range =grid_max(entire meadow), so any bird anywhere kept the flee alive.FLEEING is in
ACTIVE_ENERGY_DRAIN_STATES, so energy bled away until the butterfly died.Root cause (client)
_evaluate_fleeing:best == null or flee_targets.has()was wrong — entered flee block when no threat was foundVector2.ZERO→ butterfly frozen in placeFixes
server/.../interaction_actors.pyserver/.../movement_actors.pyclient/.../agency.gdclient/.../world_model.gdflee_dir,flee_dir_expiry,FLEE_DIR_TIMEOUTfieldsHUD: Per-entity-type stat legend
Added a legend in the top-right corner that auto-shows when selecting an entity, explaining each stat icon:
All values shown as (0–100) except age which shows (ticks).
Files changed
client/godot/scenes/main.gd— legend label,\_build_legend(), visibility togglingclient/godot/scenes/main.tscn— LegendLabel nodeclient/godot/scripts/agency.gd— flee logic fix + direction cachingclient/godot/scripts/autoloads/world_model.gd— flee persistence fieldsserver/ecosim/actors/interaction_actors.py— FleeActor entry-only guardserver/ecosim/actors/movement_actors.py— MovementActor FLEEING skipTesting
All 39 unit tests pass (actor tests + movement actor tests).